//! 可以如下面一样使用
//! ```rust
//! use crate::bit_struct::bit_struct;
//! bit_struct! {
//!     BitStruct(u32) {
//!         field_a: 3,
//!         field_b: 10,
//!         field_c: 10
//!     }
//! }
//! ```
//! 生成的代码
//! ```rust
//! pub struct BitStruct(u32);
//! impl BitStruct {
//!     fn new(value: u32) -> Self {
//!         Self(value)
//!     }
//!     fn value(&self) -> u32 {
//!         self.0    
//!     }
//!     fn field_a(&self) -> u32 {
//!         let mask = (1 << 3) - 1;
//!         ((self.0) >> 0) & mask
//!     }
//!     fn field_b(&self) -> u32 {
//!         let mask = (1 << 10) - 1;
//!         ((self.0) >> (0 + 3)) & mask
//!     }
//!     fn field_c(&self) -> u32 {
//!         let mask = (1 << 10) - 1;
//!         ((self.0) >> ((0 + 3) + 10)) & mask
//!     }
//! }
//! ```
//! 最好只用 无符号类型，有符号自己把握。。。

#[macro_export]
macro_rules! bit_struct {
    { $name: ident ( $type: ty ) { $($field_name: ident : $field_len: expr),+ } } => {
        pub struct $name($type);

        impl $name {
            pub fn new(value: $type) -> Self {
                Self(value)
            }

            pub fn value(&self) -> $type {
                self.0
            }

            bit_struct!{@field, $type, 0 $(,$field_name : $field_len)* }
        }
    };

    // 生成 field
    (@field, $type: ty, $begin: expr) => {};
    (@field, $type: ty, $begin: expr, $field_name: ident : $field_len: expr  $(,$a:ident : $b:expr)*) => {
        pub fn $field_name(&self) -> $type {
            let mask = (1 << $field_len) - 1;
            ((self.0) >> $begin) & mask
        }

        bit_struct!{@field, $type, ($begin + $field_len) $(,$a : $b)*}
    };
}

#[cfg(test)]
mod test {
    use super::bit_struct;

    bit_struct! {
        BitStruct(u32) {
            a: 1,
            b: 3,
            c: 10
        }
    }
    #[test]
    fn it_works() {
        let a = BitStruct::new(0b1100_101_1);
        assert_eq!(a.value(), 0b1100_101_1);
        assert_eq!(a.a(), 0b1);
        assert_eq!(a.b(), 0b101);
        assert_eq!(a.c(), 0b1100);
    }
}
